#ifndef __INC_CONTROLLER
#define __INC_CONTROLLER

/*
 * Forward declare Controller because it's circularly referenced by other classes.
 */
typedef struct controller Controller;

#include "../alu/alu.h"
#include "../alu/register.h"
#include "../alu/registerset.h"
#include "../cpu/cpu.h"
#include "../memory/memory.h"

#define OPCODE_BITMASK 0xf000
#define OPCODE_RSHIFT 12

#define OP_ADD  0x1
#define OP_AND  0x5
#define OP_BR   0x0
#define OP_HALT 0xF
#define OP_JMP  0xC
#define OP_LD   0x2
#define OP_LDR  0x6
#define OP_LEA  0xE
#define OP_NOT  0x9
#define OP_ST   0x3
#define OP_STR  0x7
#define OP_SUB  0xD

#define BRPCOFFSET_BITMASK 0x007f
#define PCOFFSET_BITMASK 0x01ff
#define REGOFFSET_BITMASK 0x003f

#define BASE_REG_BITMASK 0x01c0
#define BASG_REG_RSHIFT 6

#define SR1_BITMASK 0x01c0
#define SR1_RSHIFT 6
#define SR2_BITMASK 0x0007
#define SR2_RSHIFT 0
#define DR_BITMASK 0x0e00
#define DR_RSHIFT 9

#define IMMFLAG_BITMASK 0x0020
#define IMM_BITMASK 0x1f

#define BR_N_BITMASK 0x0800
#define BR_Z_BITMASK 0x0400
#define BR_P_BITMASK 0x0200
#define BR_O_BITMASK 0x0100
#define BR_C_BITMASK 0x0080

/*
 * The Controller type.
 */
struct controller
{
	/*
	 * A reference to the CPU.
	 */
	Cpu *cpu;

	/*
	 * A reference to the ALU.
	 */
	Alu *alu;

	/*
	 * A reference to the register file.
	 */
	RegisterSet *register_file;

	/*
	 * A reference to the memory bank.
	 */
	Memory *memory;

	/*
	 * The bit-masked instruction opcode for the current IR.
	 */
	Register current_instruction;

	/*
	 * The address in memory that must be used for the current instruction.
	 */
	Register computed_memory_address;

	/*
	 * An immediate source register.
	 */
	Register source_1;

	/*
	 * An immediate source register.
	 */
	Register source_2;

	/*
	 * An immediate source register.
	 */
	Register result;
};

/*
 * Initializes a new controller.
 * cpu: A reference to the CPU.
 * alu: A reference to the ALU.
 * memory: A reference to the memory bank.
 * register_set: A reference to the register set.
 */
Controller *new_controller(Cpu *cpu, Alu *alu, Memory *memory, RegisterSet *register_file);

/*
 * Steps through the next instruction.
 */
void controller_step(Controller *controller);

/*
 * Frees the memory associated with this controller.
 */
void delete_controller(Controller *controller);

#endif
